﻿using System.Collections.Generic;
using Business.Entities;
using Business.Entities.Actions;
using System;
using Newtonsoft.Json;
using System.Text;

namespace Business.Entities 
{
    /// <summary>
    /// Root object for json model with list of tasklists
    /// </summary>
    [Serializable]
    public class TasksRoot : NilzBusinessBase<TasksRoot>
    {
        public long latest_sync_point;
        public long response_time;
        /// <summary>
        /// The default tasks loaded initially. 
        /// </summary>
        public List<Task> tasks;

        /// <summary>
        /// List of task lists
        /// </summary>
        public List<TaskList> lists;

        /// <summary>
        /// Result/error message after a post 
        /// </summary>
        public List<Result> results;


        public TasksRoot()
        {
            lists = new List<TaskList>();
            tasks = new List<Task>();
        }

        /// <summary>
        /// Connects the loose tasks to the correct task list
        /// </summary>
        internal void AddTasksToList()
        {
            foreach (Task task in tasks)
            {
                var list = GetList(task.list_id[0]);
                list.Replace(task);
            }
        }

        /// <summary>
        /// Returns the task list with the specified id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public TaskList GetList(string id)
        {
            foreach (var list in lists)
            {
                if (list != null && list.id == id) return list;
            }
            return null;
        }

        /// <summary>
        /// Returns the task list with the specified name
        /// </summary>
        /// <param name="name">Name</param>
        public TaskList GetListByName(string name)
        {
            if (name == TaskList.DefaultListName) name = String.Empty;
            if (name == null) name = String.Empty;
            foreach (var list in lists)
            {

                if (list != null)
                {
                    string cmpName = list.name;
                    if (cmpName == null || cmpName == TaskList.DefaultListName) cmpName = String.Empty;
                    if (String.Compare(name,cmpName,true) == 0) return list;
                }
            }
            return null;
        }

        /// <summary>
        /// Performs deep search of task id
        /// </summary>
        /// <param name="taskId">Task id</param>
        /// <param name="foundInList">The list in which it is found, or null</param>
        /// <returns></returns>
        public Task FindTask(string taskId, out TaskList foundInList)
        {
            foundInList = null;
            if (taskId == null) return null;
            foreach (TaskList list in lists)
            {
                if (list ==  null) continue;
                var elem = list.GetTask(taskId);
                if (elem != null)
                {
                    foundInList = list;
                    return elem;
                }
            }
            return null;
        }


        /// <summary>
        /// Builds the object graph based on Google parameters
        /// </summary>
        public void PostProcess()
        {
            foreach (TaskList list in lists)
            {
                list.PostProcess();
            }
        }

        /// <summary>
        /// Returns the largest LastModified of all tasks in the list
        /// </summary>
        /// <returns></returns>
        public DateTime GetLastModified()
        {
            DateTime maxDate = DateTime.MinValue;
            foreach (TaskList list in lists)
            {
                foreach (Task task in list.child_entity)
                {
                    if (task.LastModified > maxDate) maxDate = task.LastModified;
                }
            }
            return maxDate;
        }

        internal void Add(TaskList newList)
        {
            lists.Add(newList);
            newList.Root = this;
        }

        internal void Replace(TaskList newList)
        {
            bool found = false;
            for (int i = 0; i < lists.Count; i++)
            {
                if(lists[i].id == newList.id)
                {
                    lists[i] = newList;
                    found = true;
                    break;
                } 
            }
            if (!found) lists.Add(newList);
            newList.Root = this;
        }

        /// <summary>
        /// Moves a task from list A to list B
        /// </summary>
        /// <param name="gTask"></param>
        /// <param name="sourceList"></param>
        /// <param name="destList"></param>
        public void MoveTask(Task gTask, TaskList sourceList, TaskList destList)
        {
            if (!sourceList.child_entity.Contains(gTask))
                throw new ArgumentException("Move: source list does not contain task " + gTask);
            if (destList.child_entity.Contains(gTask))
                throw new ArgumentException("Move: destination list already contains task " + gTask);
            sourceList.Remove(gTask);
            destList.Add(gTask);
        }

        internal void PostProcessLoad()
        {
            PostProcess();
            RenameDefaultLists();
        }

        private void RenameDefaultLists()
        {
            foreach (TaskList list in lists)
            {
                if (list.name == TaskList.DefaultListName) list.name = String.Empty;
            }
        }

        /// <summary>
        /// Returns a flat list of tasks
        /// </summary>
        /// <returns></returns>
        public List<Task> GetAllTasks()
        {
            List<Task> tasks = new List<Task>();
            foreach (TaskList list in lists)
            {
                foreach (Task task in list.child_entity) tasks.Add(task);
            }
            return tasks;
        }

        public string RenderAsString()
        {
            StringBuilder sb = new StringBuilder();
            foreach (TaskList list in lists)
            {
                sb.Append("---LIST--- ["+list.name+"]" + Environment.NewLine);
                foreach (Task task in list.child_entity)
                {
                    sb.Append(task.ToString() + " GID=" + task.GoogleId + ", LastMod=" + task.LastModified + Environment.NewLine);
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// Returns a array with two elements containning duplicate list names
        /// when ignoring case at google . Null if none
        /// </summary>
        /// <returns></returns>
        public string GetDuplicateListName()
        {
            var namesUpper  = new List<String>();
            foreach (var list in lists)
            {
                if(namesUpper.Contains(list.name.ToUpper()))
                {
                    return list.name;
                }
                namesUpper.Add(list.name.ToUpper());
            }
            return null;
        }
    }
}
